﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.ComponentModel;
using System.Linq.Expressions;

namespace Relocation.Data
{
	/// <summary>
	/// 数据库访问类。
	/// </summary>
	public class DataModel : RelocationEntities
	{
		public static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

		/// <summary>
		/// 保存数据库所有表关键字字段的当前最大值
		/// </summary>
		private static Dictionary<Type, int> _primaryKeysCache = new Dictionary<Type, int>();

		public static Dictionary<Type, int> primaryKeysCache
		{
			get
			{
				return _primaryKeysCache;
			}
		}

		#region 泛型相关方法

		/// <summary>
		/// 新生成一个数据表ID.
		/// </summary>
		/// <typeparam name="TEntity">实体对象类型.</typeparam>
		/// <param name="table">The table.</param>
		/// <param name="idSelector">The id selector.</param>
		/// <returns>返回一个新ID</returns>
		public static int GenerateID<TEntity>(
		    Func<DataModel, ObjectQuery<TEntity>> table,
		    Func<TEntity, int> idSelector) where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			lock (_primaryKeysCache)
			{
				int primaryKey = 0;
				if (!_primaryKeysCache.TryGetValue(typeof(TEntity), out primaryKey))
				{
					using (DataModel model = new DataModel())
					{
						primaryKey = table(model).Any() ? table(model).Max(idSelector) : 0;
					}
				}
				primaryKey++;
				_primaryKeysCache[typeof(TEntity)] = primaryKey;
				return primaryKey;
			}
		}

		/// <summary>
		/// Generates the ID.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="entity">The entity.</param>
		/// <returns>返回一个新ID</returns>
		public static int GenerateID<TEntity>(TEntity entity)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			lock (_primaryKeysCache)
			{
				int primaryKey = 0;
				if (!_primaryKeysCache.TryGetValue(typeof(TEntity), out primaryKey))
				{
					primaryKey = 0;
				}
				primaryKey++;
				_primaryKeysCache[typeof(TEntity)] = primaryKey;
				return primaryKey;
			}
		}

		/// <summary>
		/// Gets the search string.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="entity">The entity.</param>
		/// <returns>返回生成的查询串</returns>
		private string getSearchString<TEntity>(TEntity entity)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			string condition = "";
			//string keyName = entity.EntityKey.EntityKeyValues[0].Key;
			Type entityType = entity.GetType();
			foreach (var fieldType in entityType.GetProperties())
			{
				if (fieldType.Name == "EntityState" || fieldType.Name == "EntityKey")
					continue;
				var fieldValue = fieldType.GetValue(entity, null);
				if (fieldType.PropertyType.IsValueType)
				{
					if (fieldValue != null)
					{
						if (fieldType.PropertyType.Name.StartsWith("Int"))//fieldType.Name == keyName && 
						{
							if ((int)fieldValue != 0)
							{
								if (condition != "")
									condition += " and ";
								condition += "it." + fieldType.Name + "=" + fieldValue.ToString() + "";
							}
						} else if (fieldType.PropertyType.FullName.Contains("System.Int") || fieldType.PropertyType.FullName.Contains("System.Decimal"))
						{
							if (condition != "")
								condition += " and ";
							condition += "it." + fieldType.Name + "=" + fieldValue.ToString() + "";
						} else if (fieldType.PropertyType.FullName.Contains("System.DateTime"))
						{
							if (condition != "")
								condition += " and ";
							System.DateTime value = (System.DateTime)fieldValue;
							condition += "Year(it." + fieldType.Name + ")=" + value.Year + " and Month(it." + fieldType.Name + ")=" + value.Month + " and Day(it." + fieldType.Name + ")=" + value.Day;
						}
					}
				} else if (fieldType.PropertyType.Name == "String")
				{
					if (fieldValue != null)
					{
						if (fieldValue.ToString() != "")
						{
							if (condition != "")
								condition += " and ";
							condition += "it." + fieldType.Name + " like '%" + fieldValue.ToString().Replace("'", "''") + "%'";
						}
					}
				}
			}
			return condition;
		}

		/// <summary>
		/// Searches the specified entity.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="entity">The entity.</param>
		/// <returns>返回查询结果</returns>
		public ObjectQuery<TEntity> search<TEntity>(TEntity entity)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			string condition = getSearchString(entity);
			Type thisType = this.GetType();
			ObjectQuery<TEntity> query = (ObjectQuery<TEntity>)(thisType.GetProperty(entity.GetType().Name).GetValue(new DataModel(), null));
			if (condition != "")
				query = query.Where(condition);
			log.Debug(query.ToTraceString());
			return query;
		}

		/// <summary>
		/// Searches the specified query.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="query">The query.</param>
		/// <param name="entity">The entity.</param>
		/// <returns>返回生成的查询串</returns>
		public ObjectQuery<TEntity> search<TEntity>(ObjectQuery<TEntity> query, TEntity entity)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			string condition = getSearchString(entity);
			if (condition != "")
				query = query.Where(condition);
			log.Debug(query.ToTraceString());
			return query;
		}

		/// <summary>
		/// Searches the specified entity.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="entity">The entity.</param>
		/// <param name="orderField">The order field.</param>
		/// <returns>返回生成的查询串</returns>
		public ObjectQuery<TEntity> search<TEntity>(TEntity entity, string orderField)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			string condition = getSearchString(entity);
			Type thisType = this.GetType();
			ObjectQuery<TEntity> query = (ObjectQuery<TEntity>)(thisType.GetProperty(entity.GetType().Name).GetValue(new DataModel(), null));
			if (condition != "")
				query = query.Where(condition);
			if (orderField != "")
				query = query.OrderBy("it." + orderField);
			log.Debug(query.ToTraceString());
			return query;
		}

		/// <summary>
		/// Searches the specified query.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="query">The query.</param>
		/// <param name="entity">The entity.</param>
		/// <param name="orderField">The order field.</param>
		/// <returns>返回生成的查询串</returns>
		public ObjectQuery<TEntity> search<TEntity>(ObjectQuery<TEntity> query, TEntity entity, string orderField)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			string condition = getSearchString(entity);
			if (condition != "")
				query = query.Where(condition);
			if (orderField != "")
				query = query.OrderBy("it." + orderField);
			log.Debug(query.ToTraceString());
			return query;
		}

		/// <summary>
		/// Searches the specified entity.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="entity">The entity.</param>
		/// <param name="orderField">The order field.</param>
		/// <param name="direction">The direction.</param>
		/// <returns>返回生成的查询串</returns>
		public ObjectQuery<TEntity> search<TEntity>(TEntity entity, string orderField, ListSortDirection direction)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			string condition = getSearchString(entity);
			Type thisType = this.GetType();
			ObjectQuery<TEntity> query = (ObjectQuery<TEntity>)(thisType.GetProperty(entity.GetType().Name).GetValue(new DataModel(), null));
			if (condition != "")
				query = query.Where(condition);
			if (orderField != "")
				if (direction == ListSortDirection.Ascending)
				{
					query = query.OrderBy("it." + orderField);
				} else
				{
					query = query.OrderBy("it." + orderField + " desc");
				}
			log.Debug(query.ToTraceString());
			return query;
		}





		/// <summary>
		/// Inserts the or update object.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="entity">The entity.</param>
		/// <returns>插入或更新记录数</returns>
		public int Save<TEntity>(TEntity entity)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			try
			{
				Type entityType = entity.GetType();
				if (entity.EntityState == System.Data.EntityState.Unchanged)
					return 0;
				if (entity.EntityState == System.Data.EntityState.Detached | entity.EntityState == System.Data.EntityState.Added)
				{
					//entityType.GetProperty(entity.EntityKey.EntityKeyValues[0].Key).SetValue(entity, GenerateID(entity), null);
					string entityName = entity.ToString();
					entityName = entityName.Substring(entityName.LastIndexOf('.') + 1);
					this.AddObject(entityName, entity);
				}
				return this.SaveChanges();
			} catch (Exception ex)
			{
				this.Detach(entity);
				log.Error(ex.Message);
				throw ex;
			}
		}

		/// <summary>
		/// 删除记录
		/// </summary>
		/// <param name="entity">所要删除的对象</param>
		/// <returns>删除的记录数</returns>
		/// 
		/// <typeparam name="TEntity"></typeparam><remarks></remarks>
		public int Delete<TEntity>(TEntity entity)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			try
			{
				DeleteObject(entity);
				return this.SaveChanges();
			} catch (Exception ex)
			{
				this.Detach(entity);
				log.Error(ex.Message);
				throw ex;
			}
		}

		/// <summary>
		/// Sorts the specified query.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="query">The query.</param>
		/// <param name="sortField">The Sort field.</param>
		/// <returns>排序结果</returns>
		public ObjectQuery<TEntity> sort<TEntity>(ObjectQuery<TEntity> query, string sortField)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			try
			{
				ObjectQuery<TEntity> queryReturn = query.OrderBy("it." + sortField);
				//Log.Debug(queryReturn.ToTraceString());
				return queryReturn;
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}

		/// <summary>
		/// Sorts the specified query.
		/// </summary>
		/// <typeparam name="TEntity">The type of the entity.</typeparam>
		/// <param name="query">The query.</param>
		/// <param name="sortField">The Sort field.</param>
		/// <param name="direction">The direction.</param>
		/// <returns>排序结果</returns>
		public ObjectQuery<TEntity> sort<TEntity>(ObjectQuery<TEntity> query, string sortField, ListSortDirection direction)
		    where TEntity : System.Data.Objects.DataClasses.EntityObject
		{
			try
			{
				if (query == null || string.IsNullOrEmpty(sortField))
					return query;
				string directionStr = (direction == ListSortDirection.Descending) ? " desc" : "";
				ObjectQuery<TEntity> queryReturn = query.OrderBy("it." + sortField + directionStr);
				log.Debug(queryReturn.ToTraceString());
				return queryReturn;
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}

		#endregion

		#region User相关方法
		public User getUserById(int id)
		{
			try
			{
				return this.User.Where(c => c.userID == id).FirstOrDefault();
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}


		public User getUserByName(string name)
		{
			try
			{
				return this.User.Where("it.name='" + name.Replace("'", "''") + "'").FirstOrDefault();
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}

		public User getUserByNameAndPassword(string name, string password)
		{
			try
			{
				return this.User.Where("it.name='" + name.Replace("'", "''") + "' and it.password='" + password.Replace("'", "''") + "' and it.enable=true").FirstOrDefault();
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}
		#endregion

		#region Projects相关方法

		/// <summary>
		/// 根据projectID查找Projects
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public Projects getProjectById(int id)
		{
			try
			{
				return this.Projects.Where(c => c.projectID == id).FirstOrDefault();
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}
		#endregion

		#region Relocatees相关方法

		public Relocatees getRelocateesById(int id)
		{
			try
			{
				return this.Relocatees.Where(c => c.relocateID == id).FirstOrDefault();
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}

		public ObjectQuery<Relocatees> getRelocateesByProjectId(int id)
		{
			try
			{
				return this.Relocatees.Where("it.Projects.projectID = " + id);
			} catch (Exception ex)
			{
				log.Error(ex.Message);
				throw ex;
			}
		}


		#endregion

	}

	#region 实体类扩展

	public partial class User : global::System.Data.Objects.DataClasses.EntityObject
	{
		public User()
			: base()
		{
			Dictionary<Type, int> _primaryKeysCache = DataModel.primaryKeysCache;
			lock (_primaryKeysCache)
			{
				int primaryKey = 0;
				if (!_primaryKeysCache.TryGetValue(this.GetType(), out primaryKey))
				{
					using (DataModel model = new DataModel())
					{
						primaryKey = model.User.Any() ? model.User.Max(c => c.userID) : 0;
					}
				}
				_primaryKeysCache[this.GetType()] = primaryKey;
			}
		}

		static public string GetPropName(Expression<Func<User, object>> expr)
		{
			switch (expr.Body.NodeType)
			{
				case ExpressionType.MemberAccess:
					return ((MemberExpression)expr.Body).Member.Name;
				case ExpressionType.Convert:
					return ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name;
				default:
					return null;
			}
		}
	}

	public partial class Projects : global::System.Data.Objects.DataClasses.EntityObject
	{
		public bool isUsed
		{
			get
			{
				if (this.projectID == 0)
					return false;
				DataModel model = new DataModel();
				int relocatees = model.Relocatees.Where(c => c.Projects.projectID == this.projectID).Count();
				return relocatees > 0;
			}
		}

		public Projects()
			: base()
		{
			Dictionary<Type, int> _primaryKeysCache = DataModel.primaryKeysCache;
			lock (_primaryKeysCache)
			{
				int primaryKey = 0;
				if (!_primaryKeysCache.TryGetValue(this.GetType(), out primaryKey))
				{
					using (DataModel model = new DataModel())
					{
						primaryKey = model.Projects.Any() ? model.Projects.Max(c => c.projectID) : 0;
					}
				}
				_primaryKeysCache[this.GetType()] = primaryKey;
			}
		}

		static public string GetPropName(Expression<Func<Projects, object>> expr)
		{
			switch (expr.Body.NodeType)
			{
				case ExpressionType.MemberAccess:
					return ((MemberExpression)expr.Body).Member.Name;
				case ExpressionType.Convert:
					return ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name;
				default:
					return null;
			}
		}
	}

	public partial class Relocatees : global::System.Data.Objects.DataClasses.EntityObject
	{
		public Relocatees()
			: base()
		{
			Dictionary<Type, int> _primaryKeysCache = DataModel.primaryKeysCache;
			lock (_primaryKeysCache)
			{
				int primaryKey = 0;
				if (!_primaryKeysCache.TryGetValue(this.GetType(), out primaryKey))
				{
					using (DataModel model = new DataModel())
					{
						primaryKey = model.Relocatees.Any() ? model.Relocatees.Max(c => c.relocateID) : 0;
					}
				}
				_primaryKeysCache[this.GetType()] = primaryKey;
			}
		}
		/// <summary>
		/// 搜索时是否将status纳入搜索条件，默认为是（True）
		/// </summary>
		public bool IsSearchStatus = true;

		/// <summary>
		/// 返回查询条件字符串
		/// </summary>
		public string GetSearchString()
		{
			string condition = "";
			//string keyName = entity.EntityKey.EntityKeyValues[0].Key;
			Type entityType = this.GetType();
			foreach (var fieldType in entityType.GetProperties())
			{
				if (fieldType.Name == "EntityState" || fieldType.Name == "EntityKey")
					continue;
				var fieldValue = fieldType.GetValue(this, null);
				if (fieldType.PropertyType.IsValueType)
				{
					if (fieldValue != null)
					{
						if (fieldType.PropertyType.Name.StartsWith("Int"))//fieldType.Name == keyName && 
						{
							// if ((int)fieldValue != 0 || (fieldType.Name == "status"))
							if ((int)fieldValue != 0 || (fieldType.Name == "status" && this.IsSearchStatus))
							{
								if (condition != "")
									condition += " and ";
								condition += "it." + fieldType.Name + "=" + fieldValue.ToString() + "";
							}
						} else if (fieldType.PropertyType.FullName.Contains("System.Int") || fieldType.PropertyType.FullName.Contains("System.Decimal"))
						{
							if (condition != "")
								condition += " and ";
							condition += "it." + fieldType.Name + "=" + fieldValue.ToString() + "";
						} else if (fieldType.PropertyType.FullName.Contains("System.DateTime"))
						{
							if (condition != "")
								condition += " and ";
							System.DateTime value = (System.DateTime)fieldValue;
							condition += "Year(it." + fieldType.Name + ")=" + value.Year + " and Month(it." + fieldType.Name + ")=" + value.Month + " and Day(it." + fieldType.Name + ")=" + value.Day;
						} else if (fieldType.PropertyType.FullName.Contains("Boolean"))
						{
							if (condition != "")
								condition += " and ";
							Boolean value = (Boolean)fieldValue;
							condition += "it." + fieldType.Name + "=" + value.ToString();
						}
					}
				} else if (fieldType.PropertyType.Name == "String")
				{
					if (fieldValue != null)
					{
						if (fieldValue.ToString() != "")
						{
							if (condition != "")
								condition += " and ";
							condition += "it." + fieldType.Name + " like '%" + fieldValue.ToString().Replace("'", "''") + "%'";
						}
					}
				}
			}
			return condition;

		}

		static public string GetPropName(Expression<Func<Relocatees, object>> expr)
		{
			switch (expr.Body.NodeType)
			{
				case ExpressionType.MemberAccess:
					return ((MemberExpression)expr.Body).Member.Name;
				case ExpressionType.Convert:
					return ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name;
				default:
					return null;
			}
		}
	}

	#endregion
}
